import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler, OneHotEncoder
from sklearn.compose import ColumnTransformer
from sklearn.pipeline import Pipeline
from sklearn.ensemble import RandomForestClassifier, RandomForestRegressor
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score, mean_squared_error
from sklearn.cluster import KMeans

from wordcloud import WordCloud
import matplotlib.pyplot as plt
import seaborn as sns

# 1. 数据清洗和预处理
data = pd.read_csv('./data/数据分析/marketing_campaign.csv')

# 定义数值特征和类别特征
numeric_features = ['Year_Birth', 'Income', 'Kidhome', 'Teenhome', 'Recency',
                    'MntWines', 'MntFruits', 'MntMeatProducts', 'MntFishProducts',
                    'MntSweetProducts', 'MntGoldProds', 'NumDealsPurchases',
                    'NumWebPurchases', 'NumCatalogPurchases', 'NumStorePurchases',
                    'NumWebVisitsMonth']

categorical_features = ['Education', 'Marital_Status']

# 处理缺失值
data[numeric_features] = data[numeric_features].fillna(data[numeric_features].mean())
data = data.dropna(subset=categorical_features)

# 数据类型转换和特征编码
preprocessor = ColumnTransformer(
    transformers=[
        ('num', StandardScaler(), numeric_features),
        ('cat', OneHotEncoder(), categorical_features)
    ]
)

# 2. 特征工程和模型训练
X = data.drop(['ID', 'Response'], axis=1)
y = data['Response']

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# 定义模型
models = {
    'RandomForest': RandomForestClassifier(random_state=42),
    'LogisticRegression': LogisticRegression(max_iter=1000)
}

pipelines = {}
for name, model in models.items():
    pipelines[name] = Pipeline([
        ('preprocessor', preprocessor),
        ('classifier', model)
    ])

# 训练模型
for name, pipeline in pipelines.items():
    pipeline.fit(X_train, y_train)

# 3. 模型评估与对比
for name, pipeline in pipelines.items():
    y_pred = pipeline.predict(X_test)
    print(f'{name} Accuracy: {accuracy_score(y_test, y_pred)}')

# 4. 利用客户的购买历史等特征分析购买偏好（此部分需要具体的数据分析代码，这里仅提供思路）
# 可以通过分析MntWines, MntFruits等购买金额特征与Response的关系，或者使用聚类算法对客户进行分群。

# 5. 构建客户价值评分模型
# 使用随机森林回归模型预测客户的总购买金额，并作为客户价值的评分依据。
# 首先，我们需要计算每个客户的总购买金额作为目标变量。
data['TotalPurchase'] = data['MntWines'] + data['MntFruits'] + data['MntMeatProducts'] + data['MntFishProducts'] + data['MntSweetProducts'] + data['MntGoldProds']

# 划分特征和目标变量
X_value = data.drop(['ID', 'Response', 'TotalPurchase'], axis=1)
y_value = data['TotalPurchase']

# 划分训练集和测试集
X_train_value, X_test_value, y_train_value, y_test_value = train_test_split(X_value, y_value, test_size=0.2, random_state=42)

# 定义随机森林回归模型
value_model = RandomForestRegressor(random_state=42)

# 创建预处理和模型的管道
pipeline_value = Pipeline([
    ('preprocessor', preprocessor),
    ('regressor', value_model)
])

# 训练模型
pipeline_value.fit(X_train_value, y_train_value)

# 预测测试集并评估模型
y_pred_value = pipeline_value.predict(X_test_value)
mse = mean_squared_error(y_test_value, y_pred_value)
print(f'Customer Value Model MSE: {mse}')


# 利用客户的购买历史等特征分析购买偏好
# 使用柱状图展示客户对不同产品的购买情况
plt.figure(figsize=(12, 6))
products = ['MntWines', 'MntFruits', 'MntMeatProducts', 'MntFishProducts', 'MntSweetProducts', 'MntGoldProds']
data[products].mean().plot(kind='bar')
plt.title('Average Purchase Amount of Different Products')
plt.xlabel('Products')
plt.ylabel('Average Purchase Amount')
plt.show()

# 使用词云图展示购买金额最高的产品
text = ' '.join([f"{product}:{round(value,2)}" for product, value in data[products].mean().items()])
wordcloud = WordCloud(width=800, height=400, background_color='white').generate(text)
plt.figure(figsize=(10, 8))
plt.imshow(wordcloud, interpolation='bilinear')
plt.axis('off')
plt.show()

# 构建客户价值评分模型部分保持不变...

# 客户价值评分的可视化
y_pred_value = pipeline_value.predict(X_test_value)  # 修正了原代码中的错误（y_pred_value = pipeline_value.pr）
plt.figure(figsize=(10, 6))
sns.histplot(y_pred_value, kde=True, color='blue')
plt.title('Distribution of Customer Value Scores')
plt.xlabel('Customer Value Score')
plt.ylabel('Frequency')
plt.show()







